﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using LINQtoLDAPDemo_Model;

namespace LINQtoLDAPDemo_Winform.Presenters
{
    class GroupMembersPresenter
    {
        private Views.frmGroupMembers view;
        private Models.NorthwindDAO dao;

        #region Constructor
        public GroupMembersPresenter(Views.frmGroupMembers _view, Models.NorthwindDAO _dao)
        {
            view = _view;
            dao = _dao;

            LoadView();
        }
        #endregion

        #region Data Binding methods
        private void LoadView()
        {
            // Bind group combo box
            Group[] allGroups = Group.GetAllGroups();
            view.SetGroupsBindingSource(allGroups);
            dao.SetCurrentGroup(view.GetSelectedGroup());

            // Bind page number displays
            BindToCurrentPageNumbers();

            RefreshView();
        }

        private void BindToCurrentPageNumbers()
        {
            view.SetNonMembersPageNumber(dao.NonMemberPageNum);
            view.SetMembersPageNumber(dao.MemberPageNum);
        }

        private void RefreshView()
        {
            bool _isMemberPage = true;

            UpdatePage(!_isMemberPage);
            UpdatePage(_isMemberPage);

            view.SetTotalNumberOfMemberPages(dao.GetTotalNumberOfPages(_isMemberPage));
            view.SetTotalNumberOfNonMemberPages(dao.GetTotalNumberOfPages(!_isMemberPage));
        }
        #endregion

        #region Group Details
        #region Group Events
        public void AddUsersToGroup(Group _group, params User[] _users)
        {
            string[] userDNs = _users.Select(u => u.DistinguishedName).ToArray();

            _group.Members = _group.Members.Union(userDNs).ToArray();

            UpdateGroupMembers(_group);

            BindToCurrentPageNumbers();
        }

        public void RemoveUsersFromGroup(Group _group, params User[] _users)
        {
            string[] userDNs = _users.Select(u => u.DistinguishedName).ToArray();

            _group.Members = _group.Members.Where(m => !userDNs.Contains(m)).Select(m => m).ToArray();

            UpdateGroupMembers(_group);

            BindToCurrentPageNumbers();
        }

        public void ChangeGroup()
        {
            dao.SetCurrentGroup(view.GetSelectedGroup());

            // Current page numbers are reset to the first pages in dao.SetCurrentGroup()
            BindToCurrentPageNumbers();

            RefreshView();
        }
        #endregion

        public void UpdateGroupMembers(Group _group)
        {
            _group.Update();

            dao.RefreshUserData();

            RefreshView();
        }
        #endregion

        #region Page Details
        #region Page Events
        public void ChangePageNumber(string _input, bool _isMember)
        {
            bool pageNumberChanged = dao.ChangeToValidPageNumber(_input, _isMember);

            if (pageNumberChanged)
            {
                UpdatePage(_isMember);
            }
            else
            {
                // Reset page number textbox controls to last valid input
                BindToCurrentPageNumbers();
            }
        }

        public void ChangePageNumber(bool _incrementNumber, bool _isMember)
        {
            int currentPageNumber = _isMember ? dao.MemberPageNum : dao.NonMemberPageNum;
            int proposedNewPageNumber = _incrementNumber ? currentPageNumber + 1 : currentPageNumber - 1;

            ChangePageNumber(proposedNewPageNumber.ToString(), _isMember);

            BindToCurrentPageNumbers();
        }
        #endregion

        private void UpdatePage(bool _isMember)
        {
            User[] newPageContents = dao.GetPageContents(_isMember);

            if (_isMember)
            {
                view.SetMembersBindingSource(newPageContents);
            }
            else
            {
                view.SetNonMembersBindingSource(newPageContents);
            }

            bool hasNextPage = IsNextPageAvailable(_isMember);
            bool hasPreviousPage = IsPreviousPageAvailable(_isMember);
            view.SetPageLinksBindingSource(_isMember, hasNextPage, hasPreviousPage);
        }
        
        private bool IsNextPageAvailable(bool _isMember)
        {
            int totalPageCount = dao.GetTotalNumberOfPages(_isMember);

            return _isMember ? dao.MemberPageNum < totalPageCount : dao.NonMemberPageNum < totalPageCount;
        }

        private bool IsPreviousPageAvailable(bool _isMember)
        {
            return _isMember ? dao.MemberPageNum > 1 : dao.NonMemberPageNum > 1;
        }
        #endregion
    }
}
